package org.misty.seckill.service.impl;

import org.misty.seckill.model.Order;
import org.misty.seckill.model.User;
import org.misty.seckill.redis.GoodsKey;
import org.misty.seckill.redis.LuaScript;
import org.misty.seckill.redis.RedisService;
import org.misty.seckill.service.GoodsService;
import org.misty.seckill.service.OrderService;
import org.misty.seckill.service.SeckillService;
import org.misty.seckill.vo.SGoodsVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;

@Service
public class SeckillServiceImpl implements SeckillService {
  @Autowired
  private GoodsService goodsService;
  @Autowired
  private OrderService orderService;
  @Autowired
  private RedisService redisService;
  @Autowired
  private LuaScript luaScript;

  @Override
  @Transactional
  public Order seckill(User user, SGoodsVo goods) {
    var n = goodsService.decrStock(goods.getSid(), 1);
    if (n > 0) {
      return orderService.createOrder(user, goods);
    } else {
      return null;
    }
  }

  @Override
  public Order getOrderById(User user, long id) {
    if (user == null || StringUtils.isEmpty(id)) {
      return null;
    }
    return orderService.findByUserAndId(user.getId(), id);
  }

  @Override
  public void putAllOnSale() {
    var goodsList = goodsService.listSecKills();
    if (goodsList != null) {
      for (var goods : goodsList) {
        var currentTime = System.currentTimeMillis();
        var endTime = goods.getEndDate().getTime();
        if (currentTime < endTime) { // 上架商品
          var sid = String.valueOf(goods.getSid());
          var expiry = (int) ((endTime - currentTime) / 1000 + 600);

          var keys = new ArrayList<String>();
          keys.add(GoodsKey.SECKILL.realKey(sid));
          keys.add(GoodsKey.SECKILL_USERS.realKey(sid));
          var values = new ArrayList<>();
          values.add(expiry);
          values.add(goods.getStartDate().getTime());
          values.add(endTime);
          values.add(goods.getStock());
          redisService.evalsha(luaScript.putOnSale(), keys, values);
        }
      }
    }
  }

  @Override
  public Long placeOrder(User user, long goodsId, long queuingId) {
    var keys = new ArrayList<String>();
    keys.add(GoodsKey.SECKILL.realKey("" + goodsId));
    keys.add(GoodsKey.SECKILL_QUEUING.realKey(GoodsKey.queuingKey(user.getId(), queuingId)));
    var values = new ArrayList<>();
    values.add(1); // 订购数量
    return (Long) redisService.evalsha(luaScript.placeOrder(), keys, values);
  }

  @Transactional
  @Override
  public void reset() {
    orderService.clearAll();
    goodsService.resetStock(30);
    putAllOnSale();
  }
}
